// perl_dl.h - use dynamically loaded perl

#define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers

#include <windows.h>

// perl sockets will redefine ENOTSOCK
#undef ENOTSOCK

#include <EXTERN.h>
#include <perl.h>
#ifdef NEED_XS
	#include "XSUB.h"
#endif

/*

Basic perl functionality

*/

typedef void (*perlfunc_sys_init3)(int* argc, char*** argv, char*** env);
#define Perl_sys_init3(a,b,c) my_Perl_sys_init3(a,b,c);

typedef void (*perlfunc_sys_term)();
#define Perl_sys_term() my_Perl_sys_term();

typedef PerlInterpreter* (*perlfunc_alloc)();
#define perl_alloc() my_perl_alloc();

typedef void (*perlfunc_construct)(pTHX);
#define perl_construct(a) my_perl_construct(a);

typedef int (*perlfunc_destruct)(pTHX);
#define perl_destruct(a) my_perl_destruct(a);

typedef void (*perlfunc_free)(pTHX);
#define perl_free(a) my_perl_free(a);

typedef int (*perlfunc_parse)(pTHX_ XSINIT_t xsinit, int argc, char** argv, char** env);
#define perl_parse(a,b,c,d,e) my_perl_parse(a,b,c,d,e);

/*

According to http://www.nntp.perl.org/group/perl.xs/2006/08/msg2303.html,
possible return values are:
	0 on success
	value passed to exit() if eval'ed code calls exit() (well perl's my_exit()).
	1 if code does C<die> or equivalent. 

*/

typedef int (*perlfunc_run)(pTHX);
#define perl_run(a) my_perl_run(a);

// to allow checking ERRSV
typedef GV** (*perlfunc_Perl_Ierrgv_ptr)(pTHX);
#define Perl_Ierrgv_ptr my_Perl_Ierrgv_ptr

/*

Running scripts (via call_argv and preequisites)

*/

// for some reason, the definition of aTHX is not making it here
// (at least, I think that's what's going on)
// so I need to redefine the macros that use it

typedef I32 (*perlfunc_Perl_call_argv)(pTHX_ const char* sub_name, I32 flags, char** argv);
#undef call_argv
#define call_argv(a,b,c) my_Perl_call_argv(my_perl,a,b,c)

typedef SV* (*perlfunc_Perl_eval_pv)(pTHX_ const char* p, I32 croak_on_error);
#undef eval_pv
#define eval_pv(a,b) my_Perl_eval_pv(my_perl,a,b)

typedef GV* (*perlfunc_Perl_gv_add_by_type)(pTHX_ GV* gv, svtype type);
#undef gv_add_by_type
#define gv_add_by_type(a,b) my_Perl_gv_add_by_type(my_perl,a,b)

typedef bool (*perlfunc_Perl_sv_2bool)(pTHX_ SV* const sv);
#undef sv_2bool
#define sv_2bool(a) my_Perl_sv_2bool(my_perl,a)

typedef char* (*perlfunc_Perl_sv_2pv_flags)(pTHX_ SV* const sv, STRLEN* const lp, const I32 flags);
#undef sv_2pv_flags
#define sv_2pv_flags(a,b,c) my_Perl_sv_2pv_flags(my_perl,a,b,c)

#ifdef NEED_XS

// some things that perl defines in a more roundabout way
// since we're definitely on Windows, we can shortcut
#undef win32_printf
#define win32_printf printf
#undef win32_malloc
#define win32_malloc malloc
#undef win32_free
#define win32_free free

typedef SV** (*perlfunc_Perl_av_fetch)(pTHX_ AV *av, I32 key, I32 lval);
#define Perl_av_fetch my_Perl_av_fetch

typedef I32 (*perlfunc_Perl_av_len)(pTHX_ AV *av);
#define Perl_av_len my_Perl_av_len

typedef SV** (*perlfunc_Perl_av_store)(pTHX_ AV *av, I32 key, SV *val);
#define Perl_av_store my_Perl_av_store

typedef void (*perlfunc_Perl_call_list)(pTHX_ I32 oldscope, AV *paramList);
#define Perl_call_list my_Perl_call_list

typedef I32 (*perlfunc_Perl_call_method)(pTHX_ const char* methname, I32 flags);
#define Perl_call_method my_Perl_call_method

typedef I32 (*perlfunc_Perl_call_pv)(pTHX_ const char* sub_name, I32 flags);
#define Perl_call_pv my_Perl_call_pv

typedef I32 (*perlfunc_Perl_call_sv)(pTHX_ SV* sv, VOL I32 flags);
#define Perl_call_sv my_Perl_call_sv

typedef void (*perlfunc_Perl_croak_nocontext)(const char* pat, ...);
#define Perl_croak_nocontext my_Perl_croak_nocontext

typedef void (*perlfunc_Perl_croak_xs_usage)(pTHX_ const CV *const cv, const char *const params);
#define Perl_croak_xs_usage my_Perl_croak_xs_usage

typedef void (*perlfunc_Perl_free_tmps)(pTHX);
#define Perl_free_tmps my_Perl_free_tmps

typedef void* (*perlfunc_Perl_get_context)();
#define Perl_get_context my_Perl_get_context

typedef HV* (*perlfunc_Perl_get_hv)(pTHX_ const char *name, I32 flags);
#define Perl_get_hv my_Perl_get_hv

typedef SV* (*perlfunc_Perl_get_sv)(pTHX_ const char *name, I32 flags);
#define Perl_get_sv my_Perl_get_sv

typedef HV* (*perlfunc_Perl_gv_stashpv)(pTHX_ const char* name, I32 flags);
#define Perl_gv_stashpv my_Perl_gv_stashpv

typedef void* (*perlfunc_Perl_hv_common_key_len)(pTHX_ HV *hv, const char *key, I32 klen_i32, const int action, SV *val, const U32 hash);
#define Perl_hv_common_key_len my_Perl_hv_common_key_len

typedef long* (*perlfunc_Perl_Iamagic_generation_ptr)(pTHX);
#define Perl_Iamagic_generation_ptr my_Perl_Iamagic_generation_ptr

typedef SV*** (*perlfunc_Perl_Icurpad_ptr)(pTHX);
#define Perl_Icurpad_ptr my_Perl_Icurpad_ptr

typedef bool* (*perlfunc_Perl_Idirty_ptr)(pTHX);
#define Perl_Idirty_ptr my_Perl_Idirty_ptr

typedef I32** (*perlfunc_Perl_Imarkstack_max_ptr)(pTHX);
#define Perl_Imarkstack_max_ptr my_Perl_Imarkstack_max_ptr

typedef I32** (*perlfunc_Perl_Imarkstack_ptr_ptr)(pTHX);
#define Perl_Imarkstack_ptr_ptr my_Perl_Imarkstack_ptr_ptr

typedef OP** (*perlfunc_Perl_Iop_ptr)(pTHX);
#define Perl_Iop_ptr my_Perl_Iop_ptr

typedef I32* (*perlfunc_Perl_Iscopestack_ix_ptr)(pTHX);
#define Perl_Iscopestack_ix_ptr my_Perl_Iscopestack_ix_ptr

typedef SV*** (*perlfunc_Perl_Istack_base_ptr)(pTHX);
#define Perl_Istack_base_ptr my_Perl_Istack_base_ptr

typedef SV*** (*perlfunc_Perl_Istack_sp_ptr)(pTHX);
#define Perl_Istack_sp_ptr my_Perl_Istack_sp_ptr

typedef SV*** (*perlfunc_Perl_Istack_max_ptr)(pTHX);
#define Perl_Istack_max_ptr my_Perl_Istack_max_ptr

typedef SV* (*perlfunc_Perl_Isv_no_ptr)(pTHX);
#define Perl_Isv_no_ptr my_Perl_Isv_no_ptr

typedef SV** (*perlfunc_Perl_ISv_ptr)(pTHX);
#define Perl_ISv_ptr my_Perl_ISv_ptr

typedef SV* (*perlfunc_Perl_Isv_yes_ptr)(pTHX);
#define Perl_Isv_yes_ptr my_Perl_Isv_yes_ptr

typedef SV* (*perlfunc_Perl_Isv_undef_ptr)(pTHX);
#define Perl_Isv_undef_ptr my_Perl_Isv_undef_ptr

typedef I32* (*perlfunc_Perl_Itmps_floor_ptr)(pTHX);
#define Perl_Itmps_floor_ptr my_Perl_Itmps_floor_ptr

typedef I32* (*perlfunc_Perl_Itmps_ix_ptr)(pTHX);
#define Perl_Itmps_ix_ptr my_Perl_Itmps_ix_ptr

typedef XPV** (*perlfunc_Perl_IXpv_ptr)(pTHX);
#define Perl_IXpv_ptr my_Perl_IXpv_ptr

typedef AV** (*perlfunc_Perl_Iunitcheckav_ptr)(pTHX);
#define Perl_Iunitcheckav_ptr my_Perl_Iunitcheckav_ptr

typedef void (*perlfunc_Perl_markstack_grow)(pTHX);
#define Perl_markstack_grow my_Perl_markstack_grow

typedef int (*perlfunc_Perl_mg_set)(pTHX_ SV* sv);
#define Perl_mg_set my_Perl_mg_set

typedef SV* (*perlfunc_Perl_newRV)(pTHX_ SV *const sv);
#define Perl_newRV my_Perl_newRV

typedef SV* (*perlfunc_Perl_newRV_noinc)(pTHX_ SV *const sv);
#define Perl_newRV_noinc my_Perl_newRV_noinc

typedef SV* (*perlfunc_Perl_newSV)(pTHX_ const STRLEN len);
#define Perl_newSV my_Perl_newSV

typedef SV* (*perlfunc_Perl_newSViv)(pTHX_ IV i);
#define Perl_newSViv my_Perl_newSViv

typedef SV* (*perlfunc_Perl_newSVpv)(pTHX_ const char *const s, const STRLEN len);
#define Perl_newSVpv my_Perl_newSVpv

typedef SV* (*perlfunc_Perl_newSVpvn)(pTHX_ const char *const s, const STRLEN len);
#define Perl_newSVpvn my_Perl_newSVpvn

typedef SV* (*perlfunc_Perl_newSVsv)(pTHX_ SV *const old);
#define Perl_newSVsv my_Perl_newSVsv

typedef SV* (*perlfunc_Perl_newSVuv)(pTHX_ const UV u);
#define Perl_newSVuv my_Perl_newSVuv

typedef SV* (*perlfunc_Perl_newSV_type)(pTHX_ const svtype type);
#define Perl_newSV_type my_Perl_newSV_type

typedef CV* (*perlfunc_Perl_newXS)(pTHX_ const char* name, XSUBADDR_t subaddr, const char* filename);
#define Perl_newXS my_Perl_newXS

typedef CV* (*perlfunc_Perl_newXS_flags)(pTHX_ const char *name, XSUBADDR_t subaddr, const char *const filename, const char *const proto, U32 flags);
#define Perl_newXS_flags my_Perl_newXS_flags

typedef void (*perlfunc_Perl_pop_scope)(pTHX);
#define Perl_pop_scope my_Perl_pop_scope

typedef void (*perlfunc_Perl_push_scope)(pTHX);
#define Perl_push_scope my_Perl_push_scope

typedef void (*perlfunc_Perl_save_int)(pTHX_ int* intp);
#define Perl_save_int my_Perl_save_int

typedef SV** (*perlfunc_Perl_stack_grow)(pTHX_ SV** sp, SV** p, int n);
#define Perl_stack_grow my_Perl_stack_grow

typedef IV (*perlfunc_Perl_sv_2iv_flags)(pTHX_ SV *const sv, const I32 flags);
#define Perl_sv_2iv_flags my_Perl_sv_2iv_flags

typedef SV* (*perlfunc_Perl_sv_2mortal)(pTHX_ SV *const sv);
#define Perl_sv_2mortal my_Perl_sv_2mortal

typedef UV (*perlfunc_Perl_sv_2uv_flags)(pTHX_ SV *const sv, const I32 flags);
#define Perl_sv_2uv_flags my_Perl_sv_2uv_flags

typedef SV* (*perlfunc_Perl_sv_bless)(pTHX_ SV *const sv, HV *const stash);
#define Perl_sv_bless my_Perl_sv_bless

typedef void (*perlfunc_Perl_sv_catpvn_flags)(pTHX_ SV *const dstr, const char *sstr, const STRLEN len, const I32 flags);
#define Perl_sv_catpvn_flags my_Perl_sv_catpvn_flags

typedef SV* (*perlfunc_Perl_sv_derived_from)(pTHX_ SV* sv, const char *const name);
#define Perl_sv_derived_from my_Perl_sv_derived_from

typedef void (*perlfunc_Perl_sv_free)(pTHX_ SV *const sv);
#define Perl_sv_free my_Perl_sv_free

typedef int (*perlfunc_Perl_sv_isobject)(pTHX_ SV* sv);
#define Perl_sv_isobject my_Perl_sv_isobject

typedef STRLEN (*perlfunc_Perl_sv_len)(pTHX_ SV *const sv);
#define Perl_sv_len my_Perl_sv_len

typedef SV* (*perlfunc_Perl_sv_mortalcopy)(pTHX_ SV *const oldsv);
#define Perl_sv_mortalcopy my_Perl_sv_mortalcopy

typedef SV* (*perlfunc_Perl_sv_newmortal)(pTHX);
#define Perl_sv_newmortal my_Perl_sv_newmortal

typedef void (*perlfunc_Perl_sv_setiv)(pTHX_ SV *const sv, const IV num);
#define Perl_sv_setiv my_Perl_sv_setiv

typedef void (*perlfunc_Perl_sv_setpv)(pTHX_ SV *const sv, const char *const ptr);
#define Perl_sv_setpv my_Perl_sv_setpv

typedef SV* (*perlfunc_Perl_sv_setref_pv)(pTHX_ SV *const rv, const char *const classname, void *const pv);
#define Perl_sv_setref_pv my_Perl_sv_setref_pv

typedef void (*perlfunc_Perl_sv_setsv_flags)(pTHX_ SV *dstr, SV *sstr, const I32 flags);
#define Perl_sv_setsv_flags my_Perl_sv_setsv_flags

typedef void (*perlfunc_Perl_sv_setuv)(pTHX_ SV *const sv, const UV num);
#define Perl_sv_setuv my_Perl_sv_setuv

typedef U8* (*perlfunc_Perl_uvuni_to_utf8_flags)(pTHX_ U8 *d, UV uv, UV flags);
#define Perl_uvuni_to_utf8_flags my_Perl_uvuni_to_utf8_flags

typedef void (*perlfunc_Perl_warn_nocontext)(const char* pat, ...);
#define Perl_warn_nocontext my_Perl_warn_nocontext

typedef void (*perlfunc_bootstrap)(pTHX_ CV* cv);

#endif

BOOL load_perl(LPCTSTR filename, int* count);
BOOL unload_perl();
